package com.fzdy.dataplatform.core.dao.impl;

import com.fzdy.dataplatform.core.dao.Dao;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.*;
import org.jboss.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2017/3/27 0027.
 */
@Transactional
public class BaseDaoImpl<T> implements Dao<T> {
    protected Logger logger = Logger.getLogger(this.getClass());

    protected Class<T> clazz;


    @Autowired
    private SessionFactory sessionFactory;

    public BaseDaoImpl() {
        ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
        this.clazz = (Class) type.getActualTypeArguments()[0];
        this.logger.debug("DAO的真实实现类是：" + this.clazz.getName());
    }

    protected Session getSession() {
        return this.sessionFactory.getCurrentSession();
    }

    public T load(Serializable id) {
        return this.getSession().load(this.clazz, id);
    }

    public T get(Serializable id) {
        T t = this.getSession().get(this.clazz, id);
        return t;
    }

    public void persist(T entity) {
        this.getSession().persist(entity);
    }

    public Serializable save(T entity) {
        Serializable save = this.getSession().save(entity);
        flush();
        return save;
    }

    public void update(T entity) {
        this.getSession().update(entity);
        flush();
    }

    public List<T> findAll() {
        Criteria crit = this.getSession().createCriteria(this.clazz);
        List<T> list=crit.list();
        return list;
    }

    public int count() {
        return ((Integer) this.getSession().createQuery("select count('id') from " + this.clazz.getSimpleName()).uniqueResult()).intValue();
    }

    public List<T> findByHql(String hql, Object... params) {
        Query query = this.getQuery(hql, params);
        return query.list();
    }

    protected Query getQuery(String hql, Object[] params) {
        Query query = this.getSession().createQuery(hql);

        for (int i = 0; params != null && i < params.length; ++i) {
            query.setParameter(i, params[i]);
        }

        return query;
    }

    public List<T> findByHqlPage(String hql, int pageNo, int pageSize, Object... params) {
        Query query = this.getQuery(hql, params);
        query.setFirstResult((pageNo - 1) * pageSize);
        query.setMaxResults(pageSize);
        return query.list();
    }

    public void deleteT(Serializable id) {
        T load = this.getSession().load(this.clazz, id);
        this.getSession().delete(load);
        flush();
    }

    Criteria createExampleLike(T example, int pageNo, int pageSize, Order order) {
        Criteria criteria = this.getSession().createCriteria(this.clazz).add(Example.create(example).enableLike(MatchMode.ANYWHERE));
        return this.createPageOrder(criteria, pageNo, pageSize, order);
    }

    public List<T> findByExampleLike(T example) {
        return this.findByExampleLike(example, MatchMode.ANYWHERE);
    }

    public List<T> findByExampleLike(T example, String order) {
        List list = this.getSession().createCriteria(this.clazz).add(Example.create(example).enableLike()).addOrder(Order.asc(order)).list();
        return list;
    }

    public List<T> findByExampleLike(T example, MatchMode matchMode) {
        List list = this.getSession().createCriteria(this.clazz).add(Example.create(example).enableLike(matchMode)).list();
        return list;
    }

    public List<T> findByExampleLike(T example, int pageNo, int pageSize) {
        return this.findByExampleLike(example, pageNo, pageSize, "id");
    }

    public List<T> findByExampleLike(T example, int pageNo, int pageSize, String order) {
        return this.findByExampleLike(example, pageNo, pageSize, Order.desc(order));
    }

    public List<T> findByExampleLike(T example, int pageNo, int pageSize, Order order) {
        List list = this.createExampleLike(example, pageNo, pageSize, order).list();
        return list;
    }

    public long countByExampleLike(T example) {
        return this.countByExampleLike(example, MatchMode.ANYWHERE);
    }

    public long countByExampleLike(T example, MatchMode matchMode) {
        Long o = (Long) this.getSession().createCriteria(this.clazz).add(Example.create(example).enableLike(matchMode)).setProjection(Projections.count("id")).uniqueResult();
        return o.longValue();
    }

    public List<T> findByExampleEq(T example) {
        return this.findByExampleEq(example, "id");
    }

    public List<T> findByExampleEq(T example, String order) {
        return this.findByExampleEq(example, Order.desc(order));
    }

    public List<T> findByExampleEq(T example, Order order) {
        List list = this.getSession().createCriteria(this.clazz).add(Example.create(example)).addOrder(order).list();
        return list;
    }

    public List<T> findByExampleEq(T example, int pageNo, int pageSize) {
        return this.findByExampleEq(example, pageNo, pageSize, "id");
    }

    public List<T> findByExampleEq(T example, int pageNo, int pageSize, String order) {

        return this.findByExampleEq(example, pageNo, pageSize, Order.desc(order));
    }

    public List<T> findByExampleEq(T example, int pageNo, int pageSize, Order order) {
        Criteria criteria = this.getSession().createCriteria(this.clazz).add(Example.create(example));
        List list = this.createPageOrder(criteria, pageNo, pageSize, order).list();
        return list;
    }

    public long countByExampleEq(T example) {
        Criteria criteria = this.getSession().createCriteria(this.clazz).add(Example.create(example));
        return this.countCriteria(criteria);
    }

    public List<T> findByExampleEqNeProperty(T example, Map<String, Object> neqProperty) {
        return this.findByExampleEqNeProperty(example, neqProperty, "id");
    }

    public List<T> findByExampleEqNeProperty(T example, Map<String, Object> neqProperty, String order) {
        return this.findByExampleEqNeProperty(example, neqProperty, Order.desc(order));
    }

    public List<T> findByExampleEqNeProperty(T example, Map<String, Object> neqProperty, Order order) {
        Criteria criteria = this.getSession().createCriteria(this.clazz).add(Example.create(example)).addOrder(order);
        this.addNeProperty(neqProperty, criteria);
        return criteria.list();
    }

    public List<T> findByExampleEqNeProperty(T example, int pageNo, int pageSize, Map<String, Object> neqProperty, Order order) {
        Criteria criteria = this.getSession().createCriteria(this.clazz).add(Example.create(example));
        this.createPageOrder(criteria, pageNo, pageSize, order);
        this.addNeProperty(neqProperty, criteria);
        return criteria.list();
    }

    public List<T> findByExampleEqNeProperty(T example, int pageNo, int pageSize, Map<String, Object> neqProperty) {
        return this.findByExampleEqNeProperty(example, pageNo, pageSize, neqProperty, "id");
    }

    public List<T> findByExampleEqNeProperty(T example, int pageNo, int pageSize, Map<String, Object> neqProperty, String order) {
        return this.findByExampleEqNeProperty(example, pageNo, pageSize, neqProperty, Order.desc(order));
    }

    public long countByExampleEqNeProperty(T example, Map<String, Object> neqProperty) {
        Criteria criteria = this.getSession().createCriteria(this.clazz).add(Example.create(example));
        this.addNeProperty(neqProperty, criteria);
        return this.countCriteria(criteria);
    }

    private void addNeProperty(Map<String, Object> neqProperty, Criteria criteria) {
        Iterator var3 = neqProperty.keySet().iterator();

        while (var3.hasNext()) {
            String key = (String) var3.next();
            criteria.add(Restrictions.ne(key, neqProperty.get(key)));
        }

    }

    public Criteria createPageOrder(Criteria criteria, int pageNo, int pageSize, Order order) {
        return criteria.setFirstResult((pageNo - 1) * pageSize).setMaxResults(pageSize).addOrder(order);
    }

    protected long countCriteria(Criteria criteria) {
        Long result = (Long) criteria.setProjection(Projections.count("id")).uniqueResult();
        if (result == null) {
            result = Long.valueOf(0L);
        }

        return result.longValue();
    }

    public boolean has(T example) {
        long count = this.countByExampleEq(example);
        return count > 0L;
    }

    public void flush() {
        this.getSession().flush();
    }

    public int execUpdateSQL(String sql) {
        return this.getSession().createSQLQuery(sql).executeUpdate();
    }

    public void batchDelete(Serializable[] ids) {
        if (ids==null||ids.length==0){
            return;
        }
        String hql = "";
        for (int i = 0; i < ids.length; i++) {
            if (i == 0) {
                hql = "id=" + ids[i];
            } else {
                hql = hql + " or id=" + ids[i];
            }
        }
        Session session = this.getSession();
        Query q = session.createQuery("delete from " + clazz.getName() + " where " + hql);
        q.executeUpdate();
    }
}
